package com.easylinkin.linkappapi.knowledgebase.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.easylinkin.linkappapi.common.exceptions.BusinessException;
import com.easylinkin.linkappapi.common.utils.file.FileExt;
import com.easylinkin.linkappapi.common.utils.file.ZipFileUtil;
import com.easylinkin.linkappapi.event.EventMulticaster;
import com.easylinkin.linkappapi.event.KnowledgeAutoZipEvent;
import com.easylinkin.linkappapi.facerecognition.service.oss.ObjectStorageInternalService;
import com.easylinkin.linkappapi.knowledgebase.entity.BaseRefType;
import com.easylinkin.linkappapi.knowledgebase.entity.BaseRefUser;
import com.easylinkin.linkappapi.knowledgebase.entity.KnowledgeBase;
import com.easylinkin.linkappapi.knowledgebase.entity.KnowledgeType;
import com.easylinkin.linkappapi.knowledgebase.mapper.BaseRefTypeMapper;
import com.easylinkin.linkappapi.knowledgebase.mapper.BaseRefUserMapper;
import com.easylinkin.linkappapi.knowledgebase.mapper.KnowledgeBaseMapper;
import com.easylinkin.linkappapi.knowledgebase.mapper.KnowledgeTypeMapper;
import com.easylinkin.linkappapi.knowledgebase.service.KnowledgeBaseService;
import com.easylinkin.linkappapi.knowledgebase.vo.BatchAddVO;
import com.easylinkin.linkappapi.knowledgebase.vo.BatchUpateTypeVO;
import com.easylinkin.linkappapi.security.constant.LinkappUserConstant;
import com.easylinkin.linkappapi.security.context.LinkappUserContextProducer;
import com.easylinkin.linkappapi.security.entity.LinkappUser;
import com.easylinkin.linkappapi.security.mapper.LinkappUserMapper;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

/**
 * <p>
 * 知识库表 服务实现类
 * </p>
 *
 * @author xy
 * @since 2021-12-02
 */
@Service
@Slf4j
public class KnowledgeBaseServiceImpl extends
    ServiceImpl<KnowledgeBaseMapper, KnowledgeBase> implements KnowledgeBaseService {

  @Resource
  private LinkappUserContextProducer linkappUserContextProducer;

  @Resource
  private KnowledgeTypeMapper knowledgeTypeMapper;

  @Override
  public IPage<KnowledgeBase> getKnowledgeBasePage(Page page, KnowledgeBase knowledgeBase) {
    knowledgeBase.setUserId(linkappUserContextProducer.getNotNullCurrent().getId());
    // 租户id 过滤
    knowledgeBase.setTenantId(linkappUserContextProducer.getNotNullCurrent().getTenantId());
    IPage<KnowledgeBase> knowledgeBasePage = baseMapper.getKnowledgeBasePage(page, knowledgeBase);
    return knowledgeBasePage;
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public void addKnowledgeBase(KnowledgeBase knowledgeBase) {
    // 校验内容
    // 校验 知识类别下 重名校验 返回类别名称
    checkRepeatNameByTypes(knowledgeBase.getName(), knowledgeBase.getTypes(), null);

    if (StringUtils.isNotEmpty(knowledgeBase.getAttachments())) {
      // 校验 附件数量
      checkAttachmentsNum(knowledgeBase.getAttachments());
    }

    knowledgeBase.setCreateTime(new Date());
    knowledgeBase.setCreatorId(linkappUserContextProducer.getCurrent().getId().toString());
    knowledgeBase.setCreator(linkappUserContextProducer.getCurrentUsername());
    knowledgeBase.setModifyTime(new Date());
    knowledgeBase.setModifier(linkappUserContextProducer.getCurrentUsername());
    knowledgeBase.setTenantId(linkappUserContextProducer.getNotNullCurrent().getTenantId());
    baseMapper.insert(knowledgeBase);
    // 修改知识 和 知识类别 关联关系
    setKnowledgeType(knowledgeBase.getTypes(), knowledgeBase.getId());
    // 修改知识 和 用户 访问权限关联关系
    if (null != knowledgeBase.getPermissionScope() && 1 == knowledgeBase.getPermissionScope()
        && StringUtils.isNotEmpty(knowledgeBase.getPermissionUsers())) {
      setUser(knowledgeBase.getPermissionUsers(), knowledgeBase.getId());
    }
    // 生成自动打包知识zip
    if (StringUtils.isNotEmpty(knowledgeBase.getAttachments())) {
      List<String> attachment = Arrays.asList(knowledgeBase.getAttachments().split(","));
      if (attachment.size() > 1) {
        EventMulticaster.publishEvent(new KnowledgeAutoZipEvent(knowledgeBase));
      }
    }
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public void updateKnowledgeType(KnowledgeBase knowledgeBase) {
    Long id = knowledgeBase.getId();
    KnowledgeBase old = baseMapper.selectById(id);
    if (old == null) {
      throw new BusinessException("知识不存在");
    }
    // 1.校验权限
    LinkappUser currentUser = linkappUserContextProducer.getNotNullCurrent();
    // 只有创建人和系统管理员可以操作
    if (!currentUser.getId().toString().equals(old.getCreatorId()) && !LinkappUserConstant.ADMIN_TYPE
        .equals(currentUser.getType())) {
      throw new BusinessException("只有创建人和系统管理员可以操作");
    }
    // 2.校验内容
    List<KnowledgeType> excludeTypes = knowledgeTypeMapper.findTypeByKnowledgeId(old.getId());
    // 校验 知识类别下 重名校验 返回类别名称
    checkRepeatNameByTypes(knowledgeBase.getName(), knowledgeBase.getTypes(), excludeTypes);
    if (StringUtils.isNotEmpty(knowledgeBase.getAttachments())) {
      // 校验 附件数量
      checkAttachmentsNum(knowledgeBase.getAttachments());
    }else{
      knowledgeBase.setAttachmentsZipUrl(null);
    }
    knowledgeBase.setModifyTime(new Date());
    knowledgeBase.setModifier(linkappUserContextProducer.getCurrentUsername());
    baseMapper.updateById(knowledgeBase);
    // 修改知识 和 知识类别 关联关系
    setKnowledgeType(knowledgeBase.getTypes(), knowledgeBase.getId());
    // 修改知识 和 用户 访问权限关联关系
    if (null != knowledgeBase.getPermissionScope() && 1 == knowledgeBase.getPermissionScope()
        && StringUtils.isNotEmpty(knowledgeBase.getPermissionUsers())) {
      setUser(knowledgeBase.getPermissionUsers(), knowledgeBase.getId());
    }
    // 生成自动打包知识zip
    if (StringUtils.isNotEmpty(knowledgeBase.getAttachments())&&!knowledgeBase.getAttachments().equals(old.getAttachments())) {
      List<String> attachment = Arrays.asList(knowledgeBase.getAttachments().split(","));
      if (attachment.size() > 1) {
        EventMulticaster.publishEvent(new KnowledgeAutoZipEvent(knowledgeBase));
      }
    }
  }

  @Resource
  private BaseRefTypeMapper baseRefTypeMapper;

  @Resource
  private BaseRefUserMapper baseRefUserMapper;

  @Override
  @Transactional(rollbackFor = Exception.class)
  public void deleteKnowledgeBaseById(Long id) {
    KnowledgeBase old = baseMapper.selectById(id);
    if (old == null) {
      throw new BusinessException("知识不存在");
    }
    // 1.校验权限
    LinkappUser currentUser = linkappUserContextProducer.getNotNullCurrent();
    // 只有创建人和系统管理员可以操作
    if (!currentUser.getId().toString().equals(old.getCreatorId()) && !LinkappUserConstant.ADMIN_TYPE
        .equals(currentUser.getType())) {
      throw new BusinessException("只有创建人和系统管理员可以操作");
    }
    // 1.删除关联的类型
    QueryWrapper<BaseRefType> queryWrapper = new QueryWrapper();
    queryWrapper.eq("knowledge_id_", id);
    baseRefTypeMapper.delete(queryWrapper);
    // 2.删除关联的用户
    QueryWrapper<BaseRefUser> queryWrapper1 = new QueryWrapper();
    queryWrapper1.eq("knowledge_id_", id);
    baseRefUserMapper.delete(queryWrapper1);
    // 3.删除知识
    baseMapper.deleteById(id);
  }

  /**
   * 校验 知识类别下 重名校验 返回类别名称
   */
  private void checkRepeatNameByTypes(String name, String types, List<KnowledgeType> excludeTypes) {
    List<KnowledgeType> typeList = new ArrayList<>();
    if (StringUtils.isNotEmpty(types)) {
      String[] ids = types.split(",");
      for (int i = 0; i < ids.length; i++) {
        Long typeId = Long.parseLong(ids[i]);
        KnowledgeType type = knowledgeTypeMapper.selectById(typeId);
        if (null != type) {
          typeList.add(type);
        }
      }
    }
    String tenantId = linkappUserContextProducer.getNotNullCurrent().getTenantId();
    if (CollectionUtils.isEmpty(typeList)) {
      throw new BusinessException("知识类别标签不能为空");
    }
    if (!CollectionUtils.isEmpty(excludeTypes)) {
      List<Long> excludeTypeIds = excludeTypes.stream().map(KnowledgeType::getId).collect(Collectors.toList());
      typeList = typeList.stream().filter(p -> !excludeTypeIds.contains(p.getId()))
          .collect(Collectors.toList());
    }
    if (!CollectionUtils.isEmpty(typeList)) {
      for (KnowledgeType type : typeList) {
        List<KnowledgeBase> knowledgeBases = baseMapper
            .findByTypeIdAndNameAndTenantId(type.getId(), name, tenantId);
        if (!CollectionUtils.isEmpty(knowledgeBases)) {
          throw new BusinessException("知识类别【" + type.getName() + "】下有重复名称【" + name + "】");
        }
      }

    }

  }

  /**
   * 校验 附件数量 最多10个附件
   */
  private void checkAttachmentsNum(String attachments) {
    List<String> attachment = Arrays.asList(attachments.split(","));
    if (attachment.size() > 10) {
      throw new BusinessException("最多支持上传10个附件");
    }
    if (attachment.size() > 1) {
      for (int i = 0; i < attachment.size(); i++) {
        String url = attachment.get(i);
        FileExt fileInfoByUrl = getFileInfoByUrl(url);
        if (null == fileInfoByUrl || null == fileInfoByUrl.getInputStream()) {
          throw new BusinessException("有未上传完的文件：【"+url+"】请稍后重试");
        }
      }
    }
  }

  private void setKnowledgeType(String types, Long id) {
    // 修改关联的类型
    QueryWrapper<BaseRefType> queryWrapper = new QueryWrapper();
    queryWrapper.eq("knowledge_id_", id);
    baseRefTypeMapper.delete(queryWrapper);
    String[] ids = types.split(",");
    for (int i = 0; i < ids.length; i++) {
      Long typeId = Long.parseLong(ids[i]);
      KnowledgeType type = knowledgeTypeMapper.selectById(typeId);
      if (null != type) {
        BaseRefType baseRefType = new BaseRefType();
        baseRefType.setKnowledgeId(id);
        baseRefType.setTypeId(typeId);
        baseRefTypeMapper.insert(baseRefType);
      }
    }
  }

  @Resource
  private LinkappUserMapper linkappUserMapper;

  private void setUser(String permissionUsers, Long id) {
    // 修改关联的类型
    QueryWrapper<BaseRefUser> queryWrapper = new QueryWrapper();
    queryWrapper.eq("knowledge_id_", id);
    baseRefUserMapper.delete(queryWrapper);
    String[] ids = permissionUsers.split(",");
    for (int i = 0; i < ids.length; i++) {
      Long typeId = Long.parseLong(ids[i]);
      LinkappUser user = linkappUserMapper.selectById(typeId);
      if (null != user) {
        BaseRefUser baseRefUser = new BaseRefUser();
        baseRefUser.setKnowledgeId(id);
        baseRefUser.setUserId(user.getId().toString());
        baseRefUserMapper.insert(baseRefUser);
      }
    }
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public void batchAdd(BatchAddVO batchAddVO) {
    // 校验 附件数量 不能大于10
    checkAttachmentsNum(batchAddVO.getAttachments());
    String[] jsonArray = batchAddVO.getAttachments().split(",");
    // 校验 附件数量 不能小于1
    if (jsonArray.length == 0) {
      throw new BusinessException("批量发布知识，至少上传一个文件");
    }
    for (int i = 0; i < jsonArray.length; i++) {
      String url = jsonArray[i];
      if (StringUtils.isEmpty(url)) {
        continue;
      }
      if (StringUtils.isNotEmpty(url)) {
        String fileName = url.substring(url.lastIndexOf("/"));
        KnowledgeBase knowledgeBase = new KnowledgeBase();
        String name = fileName
            .substring(0, fileName.lastIndexOf("."));
        name = name.substring(name.indexOf("-") + 1);
        knowledgeBase.setName(name);
        knowledgeBase.setTypes(batchAddVO.getTypes());
        knowledgeBase.setPermissionScope(batchAddVO.getPermissionScope());
        knowledgeBase.setPermissionUsers(batchAddVO.getPermissionUsers());
        knowledgeBase.setAttachments(url);
        addKnowledgeBase(knowledgeBase);
      } else {
        throw new BusinessException("您上传的文件【" + url + "】有问题");
      }
    }
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public void batchUpdateType(BatchUpateTypeVO batchUpateTypeVO) {
    List<Long> ids = batchUpateTypeVO.getIds();
    if (CollectionUtils.isEmpty(ids)) {
      throw new BusinessException("知识列表为空");
    }
    if (StringUtils.isEmpty(batchUpateTypeVO.getTypes())) {
      throw new BusinessException("知识分类为空");
    }
    List<String> reqTypeList = Arrays.asList(batchUpateTypeVO.getTypes().split(","));
    for (Long id : ids) {
      KnowledgeBase knowledgeBase = getDetailById(id);
      if (null == knowledgeBase) {
        continue;
      }
      // 【批量移动知识】找到请求中的所有新分类（不包含原分类）
      List<String> oldTypeList = Arrays.asList(knowledgeBase.getTypes().split(","));
      reqTypeList = reqTypeList.stream().filter(p -> !oldTypeList.contains(p))
          .collect(Collectors.toList());
      if (CollectionUtils.isEmpty(reqTypeList)) {
        continue;
      }
      // 【批量移动知识】 moveWay = 0 【复制到该知识分类】选项将在原知识分类保留然后新增一个一模一样的在新知识分类，
      if (0 == batchUpateTypeVO.getMoveWay()) {
        KnowledgeBase newKownLedge = new KnowledgeBase();
        newKownLedge.setName(knowledgeBase.getName());
        newKownLedge.setContent(knowledgeBase.getContent());
        newKownLedge.setAttachments(knowledgeBase.getAttachments());
        newKownLedge.setPermissionScope(knowledgeBase.getPermissionScope());
        newKownLedge.setPermissionUsers(knowledgeBase.getPermissionUsers());
        for (String type : reqTypeList) {
          newKownLedge.setTypes(type);
          addKnowledgeBase(newKownLedge);
        }
        knowledgeBase.setTypes(StringUtils.join(oldTypeList, ","));
      } else {
        // 【批量移动知识】 moveWay = 1 【移动到该知识分类】选项是从原知识分类删除掉然后新增到新知识分类；
        knowledgeBase.setTypes(StringUtils.join(reqTypeList, ","));
        updateKnowledgeType(knowledgeBase);
      }

    }
  }

  @Override
  public String downloadAttachment(Long id) {
    String fileName = "";
    KnowledgeBase old = baseMapper.selectById(id);
    if (old == null) {
      throw new BusinessException("知识不存在");
    }
    String attachments = old.getAttachments();
    if (null == attachments) {
      throw new BusinessException("该知识不存在内容可以下载");
    }
    List<String> attachment = Arrays.asList(attachments.split(","));
    if (attachment.size() < 1) {
      throw new BusinessException("该知识不存在内容可以下载");
    }
    if (attachment.size() == 1) {
      fileName = attachment.get(0);
    } else {
      fileName = old.getAttachmentsZipUrl();
    }
    return fileName;
  }

  @Override
  public KnowledgeBase getDetailById(Long id) {
    KnowledgeBase knowledgeBase = baseMapper.selectById(id);
    if (null == knowledgeBase) {
      throw new BusinessException("知识不存在");
    }
    return knowledgeBase;
  }

  @Autowired
  @Qualifier("ossInternal")
  private ObjectStorageInternalService ossClient;

  @Value("${oss.dir}")
  private String dir;

  @Value("${oss.bucket}")
  private String bucket;

  @Value("${oss.readHost}")
  private String readHost;

  @Resource
  private KnowledgeBaseMapper knowledgeBaseMapper;

  @Override
  public void knowledgeZip(KnowledgeBase knowledgeBase) {
    String fileName = null;
    if(null == knowledgeBase){
      log.error("该知识不存在");
    }
    String attachments = knowledgeBase.getAttachments();
    if (StringUtils.isEmpty(attachments)) {
      log.info("该知识不存在内容可以打包");
    }
    List<String> attachment = Arrays.asList(attachments.split(","));
    if (attachment.size() > 1) {
      List<String> fileUrlList = new ArrayList<>();
      for (int i = 0; i < attachment.size(); i++) {
        String singleFile = attachment.get(i);
        fileUrlList.add(singleFile);
      }
      List<FileExt> fileExtList = new ArrayList<>();
      for (String url : fileUrlList) {
        if (StringUtils.isNotEmpty(url)) {
          url = url.replace("+", "%2B");
          url = url.replace("&", "%26");
        } else {
          log.error("打包知识失败：名称为空");
        }
        FileExt fileInfoByUrl = getFileInfoByUrl(url);
        if (null != fileInfoByUrl && null != fileInfoByUrl.getInputStream()) {
          fileExtList.add(fileInfoByUrl);
        } else {
          log.error("打包知识失败：名称【{}】", url);
        }
      }
      //开始导出
      InputStream fileInputStream = null;
      try {
        fileInputStream = ZipFileUtil.getFileInputStream(knowledgeBase.getName(), fileExtList);
        //上传文件到oss
        String today = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
        String resultFilename =
            dir + "temp/knowledgebase/zip/" + knowledgeBase.getName() + today + ".zip";
        ossClient.putObject(bucket, resultFilename, fileInputStream);
        fileName = readHost + "/" + resultFilename;
      } catch (Exception e) {
        log.error("打包知识失败：", e);
      } finally {
        // 关闭流
        try {
          if (null != fileInputStream) {
            fileInputStream.close();
          }
        } catch (IOException e) {
          log.error("打包知识失败：", e);
        }
      }
    }

    if(StringUtils.isNotEmpty(fileName)){
      knowledgeBase.setAttachmentsZipUrl(fileName);
      knowledgeBaseMapper.updateById(knowledgeBase);
    }
  }

  public FileExt getFileInfoByUrl(String url){
    FileExt zipFileExt = new FileExt();
    //对url路径做截取
    String fileName = url.substring(url.lastIndexOf("/") + 1, url.length());
    url = url.replaceAll(readHost+"/","");
    InputStream inputStream = ossClient.getObjectInputStream(bucket,url);
    zipFileExt.setFileName(fileName);
    zipFileExt.setInputStream(inputStream);
    return zipFileExt;
  }

  public static void main(String[] args) {
//    KnowledgeBase knowledgeBase = new KnowledgeBase();
//    knowledgeBase.setId(1l);
//    knowledgeBase.setName("烟感安装指导");
//    List<KnowledgeBase> list = new ArrayList<>();
//    list.add(knowledgeBase);
//    KnowledgeBase knowledgeBase1 = new KnowledgeBase();
//    knowledgeBase1.setId(2l);
//    knowledgeBase1.setName("烟雾报警器宣传彩页");
//    List<KnowledgeBase> list2 = new ArrayList<>();
//    list2.add(knowledgeBase);
//    list2.add(knowledgeBase1);
//    list.addAll(list2);
//    System.out.println(JSON.toJSON(list));
    String url = "http://172.16.10.190:19000/linkapp/linkapp/public/temp/hiddenDangerPhotoAlbum/zip/20220818210257191.zip";
    String suffix = url.substring(url.lastIndexOf("."), url.length());
  }
}
